package com.xxx.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.vo.CourseOrderConfirm;
import com.vo.CourseOrderConfirmItem;
import com.xxx.constant.VerificationConstant;
import com.xxx.domain.*;
import com.xxx.dto.CreateOrderDto;
import com.xxx.dto.KillCreateOrderDto;
import com.xxx.dto.PreCourseOrder2RedisDto;
import com.xxx.dto.UpdateOrderStateDto;
import com.xxx.exception.GlobleBussnessException;
import com.xxx.feignclients.CourseFeignClient;
import com.xxx.mapper.CourseOrderMapper;
import com.xxx.result.JSONResult;
import com.xxx.service.ICourseOrderItemService;
import com.xxx.service.ICourseOrderService;
import com.xxx.util.AssertUtil;
import com.xxx.util.CodeGenerateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.TreeSet;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author jh
 * @since 2025-09-10
 */
@Service
@Slf4j
@Transactional
public class CourseOrderServiceImpl extends ServiceImpl<CourseOrderMapper, CourseOrder> implements ICourseOrderService {


    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private CourseFeignClient courseFeignClient;
    @Autowired
    private ICourseOrderItemService courseOrderItemService;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private CourseOrderMapper courseOrderMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 正常下单
     * 条件判断,看那些参数需要处理  token时效
     * 向订单表中插数据 课程表 课程营销表 订单表 订单明细表
     * 创建支付单,发送事务消息
     * 发送延迟消息,解决超时未支付订单
     * token 删除
     *
     * @param
     */
    @Transactional
    @Override
    public String placeOrder(CreateOrderDto createOrderDto) {
        Long loginId = 3L; //todo 从session中获取
        String courseIds = String.join(",", createOrderDto.getCourseIds());
        String key = loginId + ":" + courseIds;
        String tokenFromRedis = stringRedisTemplate.opsForValue().get(key);
        AssertUtil.isNotNull(tokenFromRedis, "token失效");
        AssertUtil.isEquals(tokenFromRedis, createOrderDto.getToken(), "token错误");
        //生成订单信息
        JSONResult jsonResult = courseFeignClient.info(courseIds);
        AssertUtil.isTrue(jsonResult.isSuccess(), jsonResult.getMessage());
        Object data = jsonResult.getData();
        String jsonString = JSONObject.toJSONString(data);
        CourseOrderConfirm courseOrderConfirm = JSONObject.parseObject(jsonString, CourseOrderConfirm.class);
        Date now = new Date();
        String orderNo = CodeGenerateUtils.generateOrderSn(loginId);
        StringBuilder sb = new StringBuilder();
        sb.append("购买课程 [");
        Integer totalCount = 0;

        //保存订单
        CourseOrder courseOrder = new CourseOrder();
        courseOrder.setOrderNo(orderNo);
        courseOrder.setCreateTime(now);
        courseOrder.setStatusOrder(CourseOrder.ORDER_STATUS_WAIT_PAY);
        courseOrder.setPayType(createOrderDto.getPayType());
        courseOrder.setTotalAmount(courseOrderConfirm.getTotalAmount());
        courseOrder.setTotalCount(totalCount);
        courseOrder.setUserId(loginId);
        //根据courseOrderConfirm组装订单信息,以及订单明细
        for (CourseOrderConfirmItem item : courseOrderConfirm.getItems()) {
            Course course = item.getCourse();
            CourseMarket courseMarket = item.getCourseMarket();
            CourseOrderItem courseOrderItem = new CourseOrderItem();
            courseOrderItem.setCourseId(course.getId());
            courseOrderItem.setCourseName(course.getName());
            courseOrderItem.setOrderNo(orderNo);
            courseOrderItem.setAmount(courseMarket.getPrice());
            courseOrderItem.setCoursePic(course.getPic());
            courseOrderItem.setCount(1);
            courseOrderItem.setCreateTime(now);
            courseOrder.getCourseOrderItemList().add(courseOrderItem);
            sb.append(course.getName() + ";");
            totalCount = courseOrderItem.getCount() + totalCount;
        }
        sb.append("],支付 [").append(courseOrderConfirm.getTotalAmount()).append("] 元");
        courseOrder.setTitle(sb.toString()); //订单标题

        //创建支付单对象
        PayOrder payOrder = new PayOrder();
        payOrder.setCreateTime(now);
        payOrder.setAmount(courseOrder.getTotalAmount());
        payOrder.setPayType(courseOrder.getPayType());
        payOrder.setOrderNo(orderNo);
        payOrder.setPayStatus(courseOrder.getStatusOrder());
        payOrder.setSubject(courseOrder.getTitle());
        payOrder.setUserId(loginId);
        payOrder.setExtParams(courseIds);
        payOrder.setId(loginId);
        payOrder.setUpdateTime(now);


        //发送事务消息:
        TransactionSendResult transactionSendResult = rocketMQTemplate.sendMessageInTransaction(
                //事务监听器组名字
                VerificationConstant.MQ_COURSEORDER_PAY_GROUP_TRANSACTI0N,
                //主题：标签
                VerificationConstant.MQ_TOPIC_0RDER + ":" + VerificationConstant.MQ_TAGS_COURSEORDER_PAYORDER,
                //消息：用作保存支付单
                MessageBuilder.withPayload(JSONObject.toJSONString(payOrder)).build(),
                //参数：用作保存课程订单和明细
                courseOrder);
        if (transactionSendResult.getSendStatus() != SendStatus.SEND_OK) {
            throw new GlobleBussnessException("下单失败,请稍后重试");
        }
        log.info("下单成功,订单编号:{}", orderNo);

        //发送延迟消息,为了处理超时未支付
        rocketMQTemplate.asyncSend(
                VerificationConstant.MQ_TOPIC_TIMEOUT_ORDER + ":" + VerificationConstant.MQ_TAGS_TIMEOUT_ORDER,
                MessageBuilder.withPayload(orderNo).build(),
                new SendCallback() {

                    @Override
                    public void onSuccess(SendResult sendResult) {
                        // 可选：记录发送成功的日志
                        log.info("延迟订单超时消息发送成功，订单号: {}", orderNo);
                    }

                    @Override
                    public void onException(Throwable throwable) {
                        // 可选：记录异常信息
                        log.error("延迟订单超时消息发送失败，订单号: {}", orderNo, throwable);
                    }
                }
                , 3000
                , 3 // 延迟级别 30秒之后消费
        );

        //删除redis中的token
        stringRedisTemplate.delete(key);
        //返回订单编号
        return orderNo;
    }

    /**
     * 保存订单和订单明细
     *
     * @param courseOrder
     */

    @Transactional   // 事务控制, 保证数据一致性
    @Override
    public void saveOrderAndItem(CourseOrder courseOrder) {
        AssertUtil.isNotNull(courseOrder, "订单和订单明细为空");
        EntityWrapper<CourseOrder> wrapper = new EntityWrapper<>();
        wrapper.eq("order_no", courseOrder.getOrderNo());
        CourseOrder courseOrderFromDB = selectOne(wrapper);
        if (courseOrderFromDB != null) {
            log.info("订单已存在,不能重复添加");
            throw new GlobleBussnessException("订单已存在,不能重复添加");
        }
        //保存订单
        insert(courseOrder);
        //批量保存订单明细
        List<CourseOrderItem> courseOrderItemList = courseOrder.getCourseOrderItemList();
        courseOrderItemList.forEach(courseOrderItem -> courseOrderItem.setOrderId(courseOrder.getId()));
        courseOrderItemService.insertBatch(courseOrderItemList);

    }

    /**
     * 根据订单编号修改订单状态
     *
     * @param updateOrderStateDto
     */
    @Override
    public void updateOrderState(UpdateOrderStateDto updateOrderStateDto) {

        courseOrderMapper.updateOrderState(updateOrderStateDto);
    }

    /**
     * 秒杀下单
     *
     * @param killCreateOrderDto
     * @return
     */
    @Override
    public String killPlaceOrder(KillCreateOrderDto killCreateOrderDto) {
        Long loginId = 3L; //todo 从session中获取
        //==============================取出预创订单==========================
        String preCourseOrderKey = "preCourseOrder:" + loginId + ":" + killCreateOrderDto.getOrderNo();
        Object o = redisTemplate.opsForValue().get(preCourseOrderKey);
        AssertUtil.isNotNull(o, "预创订单不存在");
        PreCourseOrder2RedisDto preCourseOrder2RedisDto = (PreCourseOrder2RedisDto) o;

        //===============================校验token===========================
        String key = loginId + ":" + preCourseOrder2RedisDto.getCourseId();
        String tokenFromRedis = stringRedisTemplate.opsForValue().get(key);
        AssertUtil.isNotNull(tokenFromRedis, "token失效");
        AssertUtil.isEquals(tokenFromRedis, killCreateOrderDto.getToken(), "token错误");

        //===========================生成订单信息=====================================
        JSONResult jsonResult = courseFeignClient.info(String.valueOf(preCourseOrder2RedisDto.getCourseId()));
        AssertUtil.isTrue(jsonResult.isSuccess(), jsonResult.getMessage());
        Object data = jsonResult.getData();
        String jsonString = JSONObject.toJSONString(data);
        CourseOrderConfirm courseOrderConfirm = JSONObject.parseObject(jsonString, CourseOrderConfirm.class);
        Date now = new Date();
        String orderNo = CodeGenerateUtils.generateOrderSn(loginId);
        StringBuilder sb = new StringBuilder();
        sb.append("购买课程 [");
        Integer totalCount = preCourseOrder2RedisDto.getTotalCount();

        //=============================保存订单=============================================
        CourseOrder courseOrder = new CourseOrder();
        courseOrder.setOrderNo(orderNo);
        courseOrder.setCreateTime(now);
        courseOrder.setUpdateTime(now);
        courseOrder.setStatusOrder(CourseOrder.ORDER_STATUS_WAIT_PAY);
        courseOrder.setPayType(killCreateOrderDto.getPayType());
        courseOrder.setTotalAmount(preCourseOrder2RedisDto.getTotalAmount());
        courseOrder.setTotalCount(totalCount);
        courseOrder.setUserId(loginId);

        //=====================根据courseOrderConfirm组装订单信息,以及订单明细=====================
        CourseOrderItem courseOrderItem = new CourseOrderItem();
        courseOrderItem.setCourseId(preCourseOrder2RedisDto.getCourseId());
        courseOrderItem.setCourseName(preCourseOrder2RedisDto.getCourseName());
        courseOrderItem.setOrderNo(orderNo);
        courseOrderItem.setAmount(preCourseOrder2RedisDto.getTotalAmount());
        courseOrderItem.setCoursePic(preCourseOrder2RedisDto.getCoursePic());
        courseOrderItem.setCount(totalCount);
        courseOrderItem.setCreateTime(now);
        courseOrderItem.setUpdateTime(now);
        courseOrder.getCourseOrderItemList().add(courseOrderItem);
        sb.append(preCourseOrder2RedisDto.getCourseName() + ";");
        sb.append("],支付 [").append(courseOrderConfirm.getTotalAmount()).append("] 元");
        courseOrder.setTitle(sb.toString()); //订单标题

        //============================创建支付单对象===========================================
        PayOrder payOrder = new PayOrder();
        payOrder.setCreateTime(now);
        payOrder.setUpdateTime(now);
        payOrder.setAmount(courseOrder.getTotalAmount());
        payOrder.setPayType(courseOrder.getPayType());
        payOrder.setOrderNo(orderNo);
        payOrder.setPayStatus(courseOrder.getStatusOrder());
        payOrder.setSubject(courseOrder.getTitle());
        payOrder.setUserId(loginId);
        payOrder.setExtParams(String.valueOf(preCourseOrder2RedisDto.getCourseId()));
        payOrder.setId(loginId);

        //===================================发送事务消息:=====================================
        //发送到com.xxx.mq.CourseOrderTransactionListener进行消费
        TransactionSendResult transactionSendResult = rocketMQTemplate.sendMessageInTransaction(
                //事务监听器组名字
                VerificationConstant.MQ_COURSEORDER_PAY_GROUP_TRANSACTI0N,
                //主题：标签
                VerificationConstant.MQ_TOPIC_0RDER + ":" + VerificationConstant.MQ_TAGS_COURSEORDER_PAYORDER,
                //消息：用作保存支付单
                MessageBuilder.withPayload(JSONObject.toJSONString(payOrder)).build(),
                //参数：用作保存课程订单和明细
                courseOrder);
        if (transactionSendResult.getSendStatus() != SendStatus.SEND_OK) {
            throw new GlobleBussnessException("下单失败,请稍后重试");
        }
        log.info("下单成功,订单编号:{}", orderNo);

        //=======================发送延迟消息,为了处理超时未支付======================================
        rocketMQTemplate.asyncSend(
                VerificationConstant.MQ_TOPIC_TIMEOUT_ORDER + ":" + VerificationConstant.MQ_TAGS_TIMEOUT_ORDER,
                MessageBuilder.withPayload(orderNo).build(),
                new SendCallback() {

                    @Override
                    public void onSuccess(SendResult sendResult) {
                        // 可选：记录发送成功的日志
                        log.info("延迟订单超时消息发送成功，订单号: {}", orderNo);
                    }

                    @Override
                    public void onException(Throwable throwable) {
                        // 可选：记录异常信息
                        log.error("延迟订单超时消息发送失败，订单号: {}", orderNo, throwable);
                    }
                }
                , 3000
                , 3 // 延迟级别 30秒之后消费
        );

        //==========================删除redis中的token和预创订单====================================
        stringRedisTemplate.delete(preCourseOrderKey);
        stringRedisTemplate.delete(key);
        //返回订单编号
        return orderNo;
    }
}
